package com.twd.lang.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

    /**
     * 描述：
     *
     * @Author fish
     * @Time 2022-03-14 16:53:11
     * @Version 1.0
     */

    @Component
//    @DependsOn(value = "staticParams")
    public class RedisUtils {

        @Resource
        private RedisTemplate redisTemplate;

        private String SYS_KEY_PREFIX = "twd_";


        /**
         * 给key统一加上系统的前缀
         * @param key
         * @return {@link String}
         */
        private String wrapKey(String key) {
            if (key.startsWith(SYS_KEY_PREFIX)) {
                return key;
            }
            return SYS_KEY_PREFIX + key;
        }




        /**
         * 写入缓存
         *
         * @param key
         * @param value
         * @return
         */
        public boolean set(final String key, Object value) {
            boolean result = false;
            try {
                ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
                operations.set(wrapKey(key), value);
                result = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }

        /**
         * 写入缓存设置时效时间
         *
         * @param key
         * @param value
         * @return
         */
        public boolean set(final String key, Object value, Long expireTime, TimeUnit timeUnit) {
            boolean result = false;
            try {
                ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
                operations.set(wrapKey(key), value,expireTime,timeUnit);
                result = true;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }


        public boolean setNx(final String key, final String value) {
            return 	redisTemplate.opsForValue().setIfAbsent(wrapKey(key),value);
        }

        public boolean setNx(final String key, final String value,long timeout, TimeUnit unit) {
            return 	redisTemplate.opsForValue().setIfAbsent(wrapKey(key),value,timeout,unit);
        }

        /**
         * 批量删除对应的value
         *
         * @param keys
         */
        public void remove(final String... keys) {
            for (String key : keys) {
                remove(wrapKey(key));
            }
        }

        /**
         * 批量删除key
         *
         * @param pattern
         */
        public void removePattern(final String pattern) {
            Set<Serializable> keys = redisTemplate.keys(wrapKey(pattern));
            if (keys.size() > 0) {
                redisTemplate.delete(keys);
            }
        }

        /**
         * 删除对应的value
         *
         * @param key
         */
        public boolean remove(final String key) {

            return 	redisTemplate.delete(wrapKey(key));

        }

        /**
         * 判断缓存中是否有对应的value
         *
         * @param key
         * @return
         */
        public boolean exists(final String key) {
            return redisTemplate.hasKey(wrapKey(key));
        }

        /**
         * 读取缓存
         *
         * @param key
         * @return
         */
        public Object get(final String key) {
            Object result;
            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            result = operations.get(wrapKey(key));
            return result;
        }

        public <T> T getByType(final String key, Class<T> clz) {

            ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
            Object obj = operations.get(wrapKey(key));
            T result = obj==null?null : clz.cast(obj);
            return result;
        }



        public <T> List<T> getList(final String key, Class<T> clz) {
            JSONArray json = getByType(wrapKey(key),JSONArray.class);
            if (json != null) {
                List<T> list = json.toJavaList(clz);
                return list;
            }
            return null;
        }

        /**
         * 哈希 添加
         *
         * @param key
         * @param hashKey
         * @param value
         */
        public void hmSet(String key, Object hashKey, Object value) {
            HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
            hash.put(wrapKey(key), hashKey, value);
        }

        /**
         * 哈希获取数据
         *
         * @param key
         * @param hashKey
         * @return
         */
        public Object hmGet(String key, Object hashKey) {
            HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
            return hash.get(wrapKey(key), hashKey);
        }


        /**
         * 哈希删除
         *
         * @param key     关键
         * @param hashKey
         * @return {@link Long}
         */
        public Long hmDelete(String key, String hashKey) {

            HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
            return hash.delete(wrapKey(key),hashKey);
        }

        public boolean hexists(String key, String hashKey) {

            HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
            return hash.hasKey(wrapKey(key), hashKey);
        }

        public Map<String, Object> hgetAll(String key) {

            HashOperations<String, String, Object> hash = redisTemplate.opsForHash();
            return hash.entries(wrapKey(key));
        }


        /**
         * 列表添加
         *
         * @param k
         * @param v
         */
        public void lPush(String k, Object v) {
            ListOperations<String, Object> list = redisTemplate.opsForList();
            list.rightPush(wrapKey(k), v);
        }

        /**
         * 列表获取
         *
         * @param k
         * @param l
         * @param l1
         * @return
         */
        public List<Object> lRange(String k, long l, long l1) {
            ListOperations<String, Object> list = redisTemplate.opsForList();
            return list.range(wrapKey(k), l, l1);
        }

        public long rpush(final String key, Object obj) {
            final String value = JSON.toJSONString(obj);
            return redisTemplate.opsForList().rightPush(wrapKey(key), obj);
        }



        public void lset(final String key, long index,Object obj) {
            redisTemplate.opsForList().set(wrapKey(key), index,obj);
        }

        public Long lsize(final String key) {
            return redisTemplate.opsForList().size(wrapKey(key));
        }

        public Object lpop(final String key) {
            return  redisTemplate.opsForList().leftPop(wrapKey(key));
        }

        public Object lpop(final String key, long second) {
            return  redisTemplate.opsForList().leftPop(wrapKey(key), Duration.ofSeconds(second));
        }


        /**
         * 集合添加
         *
         * @param key
         * @param value
         */
        public void sadd(String key, Object value) {
            SetOperations<String, Object> set = redisTemplate.opsForSet();
            set.add(wrapKey(key), value);
        }


        /**
         * 集合长度
         *
         * @param key
         */
        public long scard(String key) {
            SetOperations<String, String> set = redisTemplate.opsForSet();
            return set.size(wrapKey(key));
        }

        /**
         * 集合获取
         *
         * @param key
         * @return
         */
        public Set<Object> smembers(String key) {
            SetOperations<String, Object> set = redisTemplate.opsForSet();
            return set.members(wrapKey(key));
        }

        /**
         * 集合删除
         *
         * @param key
         * @return
         */
        public Long srem(String key,Object... value) {
            SetOperations<String, Object> set = redisTemplate.opsForSet();
            return set.remove(wrapKey(key),value);
        }


        /**
         * 有序集合添加
         *
         * @param key
         * @param value
         * @param scoure
         */
        public void zAdd(String key, Object value, double scoure) {
            ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
            zset.add(wrapKey(key), value, scoure);
        }

        /**
         * 有序集合获取
         *
         * @param key
         * @param scoure
         * @param scoure
         * @return
         */
        public Set<Object> rangeByScore(String key, double scoure, double scoure1) {
            ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
            return zset.rangeByScore(wrapKey(key), scoure, scoure1);
        }


        public Long incrBy(String key, int i) {
            return redisTemplate.opsForValue().increment(wrapKey(key), i);
        }

        public void expire(String key, int expire) {
            redisTemplate.expire(wrapKey(key), expire, TimeUnit.SECONDS);
        }


        public List<String> scanKeys(String regex) {
            return (List<String>)  redisTemplate.execute((RedisCallback<List<String>>) connection -> {

                List<String> binaryKeys = new ArrayList<>();

                Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions().count(Integer.MAX_VALUE).match(wrapKey(regex)).build());
                while (cursor.hasNext()) {
                    binaryKeys.add(new String(cursor.next()));
                }
                cursor.close();
                return binaryKeys;
            });
        }

        public Long ttl(String key) {
            return redisTemplate.getExpire(wrapKey(key));
        }
    }


